Skip to content

ram: Cross platform testing and support#9991

Merged
maliberty merged 25 commits into
The-OpenROAD-Project:masterfrom
braydenlouie:pdk-support
Apr 13, 2026
Merged

ram: Cross platform testing and support#9991
maliberty merged 25 commits into
The-OpenROAD-Project:masterfrom
braydenlouie:pdk-support

Conversation

@braydenlouie

@braydenlouie braydenlouie commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replaces hardcoded sky130 port names with a PDK-independent pin mapping system
  • Introduces 'PortRole' struct with 'PortRoleType' enum that is used to classify Liberty ports by role instead of name
  • Verified against both sky130hd and nangate45

Type of Change

  • New feature
  • Refactoring

Impact

RamGen is no longer tied to sky130 port naming conventions and allows using any PDK with a valid Liberty file, with pin names resolved automatically. The existing sky130 behavior is preserved.

Verification

  • I have verified that the local build succeeds (./etc/Build.sh).
  • I have run the relevant tests and they pass.
  • My code follows the repository's formatting guidelines.
  • I have signed my commits (DCO).

Related Issues

#9468
#9392

OpenROAD Contributor and others added 5 commits March 30, 2026 00:20
add test make_7x7_nangate45 exercising generate_ram with Nangate45
standard cells. Uses an intentionally odd 7-word x 1-byte (56-bit)
configuration to stress the decoder logic on a non-power-of-2 count.

also fix a latent bug in makeCellBit() where the clock-pin name probe
only checked for CLK (sky130hd) or GATE (latch cells), silently
missing CK which is the Nangate45 DFF_X1 clock pin name.
The probe chain is extended to CLK -> CK -> GATE.

Resolves The-OpenROAD-Project#9468.

Signed-off-by: OpenROAD Contributor <contributor@openroad.org>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
@braydenlouie

braydenlouie commented Mar 30, 2026

Copy link
Copy Markdown
Contributor Author

@rovinski I haven't completed testing with generate_ramyet, but the generate_ram_netlist (just placing all cells, no routing, pdngen, etc.) for Nangate45 is working. Just wanted to put this draft PR up so you can take a look at let me know if this implementation is viable.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a more robust mechanism for resolving technology-specific pin names in the RamGen class by utilizing a new PinRole system and a buildPinMap method. It also adds a new regression test for a 7x7 RAM configuration using the Nangate45 library. Several issues were identified in the review: a critical copy-paste error in the decoder logic, incorrect parameters in the new 7x7 test file and its golden Verilog output, leftover debug logging, and redundant code blocks that should be cleaned up before merging.

Comment thread src/ram/src/ram.cpp Outdated
Comment on lines +1 to +32
module RAM7x8 (
clk,
D,
Q,
addr_rw,
we
);
input clk;
input [7:0] D;
output reg [7:0] Q;
input [2:0] addr_rw;
input [0:0] we;

// memory array declaration
reg [7:0] mem[0:6];

// write logic
integer i;
always @(posedge clk) begin
for (i = 0; i < 1; i = i + 1) begin
if (we[i]) begin
mem[addr_rw][i*8 +:8] <= D[i*8 +:8];
end
end
end

// read logic
always @(*) begin
Q = mem[addr_rw];
end

endmodule

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The contents of this golden Verilog file seem incorrect for a 7x7 RAM. It appears to have been copied from an 8-bit wide RAM test and not fully updated.

Specifically:

  • The module name is RAM7x8, but should be RAM7x7.
  • The D and Q ports are 8 bits wide ([7:0]), but should be 7 bits ([6:0]).
  • The memory array mem is declared as reg [7:0], but should be reg [6:0].
  • The write logic uses an 8-bit part-select (i*8 +:8), but should use 7.

Please update this file to reflect the correct behavior for a 7-word by 7-bit RAM.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gemini is correct here. Something not right with the behavioral model.

Comment thread src/ram/src/ram.cpp Outdated
Comment on lines +119 to +147
// Resolve the clock-pin name for the storage cell by querying the
// Liberty data. This avoids hard-coding technology-specific pin names
// (e.g. "CLK", "CK") and works with any technology node.
// const char* clk_pin = nullptr;
// const char* data_in_pin = nullptr;
// auto sta_cell = network_->dbToSta(storage_cell_);
// if (sta_cell) {
// auto liberty = network_->libertyCell(sta_cell);
// if (liberty) {
// auto port_iter = liberty->portIterator();
// while (port_iter->hasNext()) {
// auto lib_port = port_iter->next();
// if (lib_port->libertyPort() && lib_port->libertyPort()->isClock()) {
// clk_pin = lib_port->name();
// }
// if (lib_port->libertyPort() &&
// lib_port->libertyPort()->isLatchData()) {
// data_in_pin = lib_port->name();
// }
// }
// delete port_iter;
// }
// }
// if (!clk_pin) {
// logger_->error(RAM,
// 12,
// "No clock pin found on storage cell {}.",
// storage_cell_->getName());
// }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This large block of commented-out code should be removed. It appears to be legacy logic for resolving pin names that has been replaced by the new buildPinMap and *_pins_ maps. Keeping dead code can be confusing for future maintenance.

Comment thread src/ram/src/ram.cpp Outdated
Comment on lines +449 to +454
logger_->info(RAM,
98,
"port name:{} dir:{} isPwrGnd:{}",
lib_port->name(),
dir->name(),
lib_port->isPwrGnd());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This info level log message inside a loop seems to be for debugging purposes. It can generate a lot of output and should be removed or changed to a more appropriate debug level before merging.

Comment thread src/ram/src/ram.cpp Outdated
Comment on lines +569 to +576
for (const auto& [role, name] : clock_gate_pins_) {
logger_->info(RAM,
99,
"Clock gate pin - Role: {}/{}, Name: {}",
static_cast<int>(role.type),
role.index,
name);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This loop for logging clock gate pins appears to be for debugging. It should be removed before merging.

Comment thread src/ram/test/make_7x7_nangate45.tcl Outdated
-word_size 7 \
-num_words 7 \
-read_ports 1 \
-read_ports 1 \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The -read_ports argument is specified twice. This line is a duplicate and should be removed.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Comment thread src/ram/include/ram/ram.h Outdated
// for map so that keys are comparable
bool operator<(const PinRole& other) const
{
return std::tie(type, index) < std::tie(other.type, other.index);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "std::tie" is directly included [misc-include-cleaner]

src/ram/include/ram/ram.h:9:

- #include <utility>
+ #include <tuple>
+ #include <utility>

Comment thread src/ram/include/ram/ram.h Outdated

private:
void findMasters();
std::map<PinRole, std::string> buildPinMap(odb::dbMaster*);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "std::map" is directly included [misc-include-cleaner]

src/ram/include/ram/ram.h:7:

- #include <memory>
+ #include <map>
+ #include <memory>

Comment thread src/ram/src/ram.cpp Outdated
return best;
}

std::map<PinRole, std::string> RamGen::buildPinMap(dbMaster* master)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "std::map" is directly included [misc-include-cleaner]

src/ram/src/ram.cpp:10:

- #include <memory>
+ #include <map>
+ #include <memory>

Signed-off-by: braydenlouie <braydenl9988@gmail.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Comment thread src/ram/include/ram/ram.h Outdated
// for map so that keys are comparable
bool operator<(const PinRole& other) const
{
return std::tie(type, index) < std::tie(other.type, other.index);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "std::tie" is directly included [misc-include-cleaner]

src/ram/include/ram/ram.h:10:

- #include <utility>
+ #include <tuple>
+ #include <utility>

Signed-off-by: braydenlouie <braydenl9988@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Comment thread src/ram/include/ram/ram.h Outdated
Ground
};

struct PinRole

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change Pin --> Port in all cases as technically you are dealing with the logical port here.

"ram"
TESTS
make_8x8
make_7x7_nangate45

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also update make_8x8 to make_8x8_sky130?

Comment thread src/ram/src/ram.cpp
}
delete port_iter;
return pin_map;
}

@rovinski rovinski Mar 31, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should have some error checking to avoid using badly defined cells. e.g.

  • Exactly 1 primary power
  • Exactly 1 primary ground
  • Exactly the number of pins which are expected for the given cell type

Or I guess I suppose you could check those things after the cell map has been made, if easier.

It doesn't need to be solved in this PR, but you should mark as a TODO item to check against various kinds of flip-flops to make sure invalid ones are flagged, e.g. scan flops, flip-flops with reset, etc. Anything that doesn't have only clk, D, and Q ports. There are occasionally some flip-flops that have a Qn (negated Q) output and those are ok, Qn is just left disconnected.

Comment on lines +1 to +32
module RAM7x8 (
clk,
D,
Q,
addr_rw,
we
);
input clk;
input [7:0] D;
output reg [7:0] Q;
input [2:0] addr_rw;
input [0:0] we;

// memory array declaration
reg [7:0] mem[0:6];

// write logic
integer i;
always @(posedge clk) begin
for (i = 0; i < 1; i = i + 1) begin
if (we[i]) begin
mem[addr_rw][i*8 +:8] <= D[i*8 +:8];
end
end
end

// read logic
always @(*) begin
Q = mem[addr_rw];
end

endmodule

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gemini is correct here. Something not right with the behavioral model.

Signed-off-by: braydenlouie <braydenl9988@gmail.com>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Comment thread src/ram/test/make_7x7_nangate45_behavioral.vok
Comment thread src/ram/test/make_7x7_nangate45.tcl Outdated
#
# Test: ram/make_7x7_nangate45
# Verifies that generate_ram works correctly with the Nangate45 technology
# node using an intentionally odd 7-word x 1-byte (56-bit) configuration

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# node using an intentionally odd 7-word x 1-byte (56-bit) configuration
# node using an intentionally odd 7-word x 7-bit (49-bit) configuration

Comment thread src/ram/test/make_7x7_nangate45.tcl Outdated
# Verifies that generate_ram works correctly with the Nangate45 technology
# node using an intentionally odd 7-word x 1-byte (56-bit) configuration
# to exercise the decoder logic on a non-power-of-2 word count.
# Addresses Issue #9468.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to include that here

Suggested change
# Addresses Issue #9468.

Comment thread src/ram/src/ram.cpp Outdated
ground_net->setSigType(odb::dbSigType::GROUND);

// find a way to get the power and ground net names associated with cells used
// finds power and gorund of a cell if not given

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// finds power and gorund of a cell if not given
// finds power and ground of a cell if not given

Comment thread src/ram/src/ram.cpp Outdated
Comment on lines +591 to +596
if (!power_pin || power_pin[0] == '\0') {
power_pin = inv_ports_[{PortRoleType::Power, 0}].c_str();
}
if (!ground_pin || ground_pin[0] == '\0') {
ground_pin = inv_ports_[{PortRoleType::Ground, 0}].c_str();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't technically sufficient. Although it would be really odd, it is still technically possible for other masters to have different power/ground names. A complete solution would be to iterate through all of the masters and collect the names into a std::set. Then, you would do a global connect on each member of the set.

99% of the time the set will only have 1 member, but it is good to handle all cases.

This is actually a separate item in #9392: "Add automatic detection of standard cell power/ground names"

It would be nice to keep that as a separate PR to only focus on one change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, I'll just keep the 'power_pin' and 'ground_pin' as required user-defined parameters now, and we can fix this in another PR.

@github-actions

github-actions Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Signed-off-by: Brayden Louie <braydenl9988@gmail.com>
Signed-off-by: Brayden Louie <braydenl9988@gmail.com>
@github-actions

github-actions Bot commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Comment thread src/ram/test/make_7x7_nangate45.ok Outdated
[WARNING ODB-0217] duplicate VIARULE (Via9Array-0) ignoring...
[INFO ODB-0394] Duplicate site FreePDK45_38x28_10R_NP_162NW_34O in Nangate45 already seen in Nangate45_tech
[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 135 library cells
[WARNING RAM-0022] No tapcell is specified.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ng45 has a tapcell, right? If not, use an x1 fill cell as the tap cell.

Comment thread src/ram/test/make_7x7_nangate45.tcl Outdated
Comment on lines +29 to +30
-ver_layer {metal4 0.28 8} \
-hor_layer {metal5 0.28 8} \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work? I thought the metals needed to be the first 2 above the first metal layer.

We generally don't want to use above M3 if it can be helped.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Nangate45's density is just too high for us to route on metal2 and metal3. Any valid combination of pitch and width has resulted in violations with the detailed router. I will note that these pitch and width dimensions don't work when tapcells are inserted, so this test will probably change.

Signed-off-by: braydenlouie <braydenl9988@gmail.com>
@github-actions

github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Signed-off-by: Brayden Louie <braydenl9988@gmail.com>
@github-actions

github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@braydenlouie braydenlouie marked this pull request as ready for review April 4, 2026 01:06
@github-actions

github-actions Bot commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@braydenlouie

Copy link
Copy Markdown
Contributor Author

@maliberty @rovinski PR is ready for review

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@rovinski rovinski requested a review from maliberty April 9, 2026 18:35
Comment thread src/ram/include/ram/ram.h Outdated
Comment on lines +72 to +76
// for map so that keys are comparable
bool operator<(const PortRole& other) const
{
return std::tie(type, index) < std::tie(other.type, other.index);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In c++20 you can use

auto operator<=>(const PortRole&) const = default;

and get all six operators

Comment thread src/ram/src/ram.cpp
Comment on lines +447 to +448
if (!tri_enable_name.empty()) {
// find and remove it from DataIn

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would a tristate enable appear as a DataIn? That doesn't appear possible in the prior loop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tristate enable pin has no distinguishing Liberty flag and is treated as an input port, so the only way to identify it is through the tristateEnable() expression on the tristate output port. Since port iteration order is arbitrary and PDK-dependent, the tristate output port may appear after the enable pin, meaning there is no guarantee the enable pin name is known before it is encountered during iteration. The other option is to do the check for the name first, before iterating over all the ports again and classifying them.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Perhaps a comment would help as it is a bit tricky

Comment thread src/ram/src/ram.cpp Outdated
master->getName(),
ground_count);
}
delete port_iter;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid manual memory management with a smart pointer and no delete

std::unique_ptr port_iter = liberty->portIterator();

Signed-off-by: braydenlouie <braydenl9988@gmail.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Comment thread src/ram/include/ram/ram.h
Comment thread src/ram/src/ram.cpp Outdated
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
Signed-off-by: braydenlouie <braydenl9988@gmail.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

Comment thread src/ram/include/ram/ram.h
Signed-off-by: braydenlouie <braydenl9988@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Signed-off-by: braydenlouie <braydenl9988@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Signed-off-by: Brayden Louie <braydenl9988@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@braydenlouie braydenlouie requested a review from maliberty April 12, 2026 23:22
@maliberty maliberty merged commit 90a90f2 into The-OpenROAD-Project:master Apr 13, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants